#include "ET++.ph"
#ifdef __GNUG__
#pragma implementation
#endif

#include "ProgressDialog.h"

#include "Class.h"
#include "Dialog.h"
#include "Box.h"
#include "TextItem.h"
#include "WindowSystem.h"
#include "Window.h"
#include "WindowPort.h"
#include "Buttons.h"
#include "String.h"
#include "Look.h"
#include "BorderItems.h"
#include "Alert_e.h"

//---- ProgressBar -------------------------------------------------------------

class ProgressBar : public VObject {
public:
	long val;
public:
	ProgressBar() : VObject(Point(20))
		{ }
	Metric GetMinSize()
		{ return gLook->ProgressBarLayout()->GetMinSize(this);  }
	void Draw(Rectangle r)
		{ gLook->ProgressBarLayout()->Adorn(this, r, (int)val); }
	void SetVal(long v);
};

void ProgressBar::SetVal(long v)
{
	val= v;
	ForceRedraw();
	if (GetWindow()) {
		WindowPort *wp= (WindowPort*) GetWindow()->GetPortDesc();
		wp->DevUpdate();
	}
}

//---- ProgressDialog ----------------------------------------------------------

const int cIdStop= cIdFirstUser + 100;

class ProgressDialog : public Dialog {
public:
	//MetaDef(ProgressDialog);
	ProgressDialog(ProgressBar *b, TextItem *t);
	void Show();
	bool IsStopped();

protected:
	VObject *DoMakeControls();
	VObject *DoMakeActions();
	void Control(int id, int part, void *val);

protected:
	ProgressBar *bar;
	TextItem *ti;
	bool quit;
};

//NewMetaImpl0(ProgressDialog, Dialog);

ProgressDialog::ProgressDialog(ProgressBar *b, TextItem *t)
												: Dialog("Progress", eWinFixed)
{
	bar= b;
	ti= t;
}

bool ProgressDialog::IsStopped()
{
	bool old= quit;
	quit= FALSE;
	return old;
}

void ProgressDialog::Show()
{
	quit= FALSE;
	bar->val= 0;
	ShowAt(gWindow, gWindow->contentRect.Center());
}

VObject *ProgressDialog::DoMakeControls()
{
	return
		new VExpander(gPoint10,
			ti,
			bar,
			0
		);
}

VObject *ProgressDialog::DoMakeActions()
{
	return new ActionButton(cIdStop, "Abort");
}

void ProgressDialog::Control(int i, int part, void *val)
{
	if (i == cIdStop)
		quit= TRUE;
	else
		Dialog::Control(i, part, val);
}

//---- ProgressImpl ------------------------------------------------------------

ProgressImpl::ProgressImpl()
{
}

ProgressImpl::~ProgressImpl()
{
	if (pb == 0)
		SafeDelete(ti);
	SafeDelete(pb);
}

void ProgressImpl::DoSetUp()
{
	gWindowSystem->SetWait();
}

void ProgressImpl::DoEnableAbort(bool)
{
	//fprintf(stderr, "ProgressImpl::SetStop: %d\n", b);
}

void ProgressImpl::DoSetMessage(const char *message)
{
	if (ti)
		ti->SetString(message);
	else
		ti= new TextItem(message);
}

bool ProgressImpl::DoSetVal()
{
	if ((pb == 0 || ! pb->IsOpen()) && curr > /* (max*2)/3 */ max) {
		timeout= FALSE;
		return FALSE;
	}

	if (bar == 0)
		bar= new ProgressBar();

	long v= (curr*bar->contentRect.extent.x)/max;

	if (v != bar->val) {
		if (pb == 0)
			pb= new ProgressDialog(bar, ti);
		if (! pb->IsOpen()) {
			bar->SetVal(v);
			pb->ShowOnWindow(gWindow);
		} else
			bar->SetVal(v);
		((WindowPort*) pb->GetWindow()->GetPortDesc())->Poll(0);

		if (pb->IsStopped()) {
			if (ShowAlert(eAlertStop, "Abort %s ?", ti->AsString()) == cIdYes) {
				DoAbort(FALSE);
				return TRUE;
			}
		}
	}
	return FALSE;
}

void ProgressImpl::DoAbort(bool skiptoend)
{
	gWindowSystem->ResetWait();
	if (pb && pb->IsOpen()) {
		if (skiptoend)
			for (long i= bar->val; i < bar->contentRect.extent.x; i++)
				bar->SetVal(i);
		pb->Close();
	}
}

